package com.share.schedule.xxl.schedule;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPath;
import com.share.common.utils.*;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 检索es错误日志 并发送到钉钉
 */
@Slf4j
@Component
public class EsErrorLogJob {
    private final static String ES_ROOT_URL = "http://es.snyq.ltd:9200";

    //2021-07-02T00:00:00.000z
    //2028-07-02T00:00:00.000z
    //统计错误日志
    private final static String STATS_ERROR_LOG_PARAM = "{ \"query\": { \"bool\": { \"must\": [ { \"range\": { \"@timestamp\": { \"gte\": \"#startTime#\", \"lt\": \"#endTime#\" } } } ], \"filter\": [ { \"term\": { \"level.keyword\": \"ERROR\" } } ] } }, \"size\": 0, \"aggs\": { \"application_name_terms\": { \"terms\": { \"field\": \"application_name.keyword\", \"size\": 100, \"order\": { \"_count\": \"asc\" } }, \"aggs\": { \"classpath_terms\": { \"terms\": { \"field\": \"classpath.keyword\", \"size\": 100, \"order\": { \"_count\": \"desc\" } } } } } } }";

    //发送错误日志
    private final static String ERROR_LOG_PARAM = "{ \"query\": { \"bool\": { \"must\": [ { \"match\": { \"level\": \"ERROR\" } }, { \"range\": { \"@timestamp\": { \"gt\": \"#startTime#\" } } } ] } }, \"sort\": [ { \"@timestamp\": { \"order\": \"desc\" } } ],\"size\": #size# }";

    //统计es错误日志
    @XxlJob("statsEsErrorLog")
    public void statsEsErrorLog() throws Exception {
        //  索引名字:0;0;
        LocalDateTime start = LocalDateTime.now();
        String jobParam = XxlJobHelper.getJobParam();
        log.info("接收到参数JobParam={}", jobParam);
        if (StringUtils.isBlank(jobParam)) {
            jobParam = "share_log_" + DateExtUtil.getDate();
        }

        List<String> list = new LinkedList<>();
        try {
            String[] split = jobParam.split(",");
            int size = split.length;
            for (int i = 0; i < size; i++) {
                String index = split[i];
                if (StringUtils.isNotBlank(index) || index.startsWith("share")) {
                    list.add(index);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        Date date = new Date();
        String startTime = DateUtil.toUtcDateTime(date, -3);
        String endTime = DateUtil.toUtcDateTime(date, 1);
        String param = STATS_ERROR_LOG_PARAM.replaceAll("#startTime#", startTime).replaceAll("#endTime#", endTime);

        List<Map> reList = new LinkedList<>();
        for (String index : list) {
            //发起请求---请求地址格式  http://0.0.0.0:9200/your_indx/_search
            String url = ES_ROOT_URL + "/" + index + "/_search";
            try {
                log.info("正在请求url={}", url);
                String res = HttpUtil.post(url, param);
                log.info("响应结果={}", res);

                Map<String, JSONArray> kMap = parseAggregationResult(res);
                if (!CollectionUtils.isEmpty(kMap)) {
                    reList.add(kMap);
                }
            } catch (Exception e) {
                log.error("请求异常url={}", url, e);
            }
        }

        if (!CollectionUtils.isEmpty(reList)) {
            String title = "统计es异常日志";
            String content = title + " " + DateUtil.getDateTime() + System.lineSeparator() + JSON.toJSONString(reList);
            DingDingUtil.sendMdMsg(title, content);
        }

        LocalDateTime end = LocalDateTime.now();
        String msg = "共耗时：{}毫秒";
        long costTime = Duration.between(start, end).toMillis();
        log.info(msg, costTime);
        XxlJobHelper.log(msg, costTime);
    }

    //统计数据解析
    private static Map<String, JSONArray> parseAggregationResult(String result) {
        Map<String, JSONArray> map = new HashMap<>();
        Object read = JSONPath.read(result, "$.aggregations.application_name_terms.buckets");
        List<JSONObject> array = (List<JSONObject>) read;
        if (!CollectionUtils.isEmpty(array)) {
            for (JSONObject param : array) {
                JSONArray buckets = param.getJSONObject("classpath_terms").getJSONArray("buckets");
                String key = param.getString("key");
                map.put(key, buckets);
            }
        }
        return map;
    }


    //错误日志提取
    @XxlJob("sendEsErrorLog")
    public void sendEsErrorLog() throws Exception {
        //  索引名字:0;0;
        LocalDateTime start = LocalDateTime.now();
        String jobParam = XxlJobHelper.getJobParam();
        log.info("接收到参数JobParam={}", jobParam);

        //计算核心参数
        int size = 1000;
        int addMinute = -30;
        try {
            int a1 = Integer.parseInt(jobParam);
            if (a1 > 0) {
                throw new RuntimeException("参数-不合规");
            }
            //覆盖参数
            addMinute = a1;
        } catch (Exception e) {
            addMinute = -30;
        }

        Date date = new Date();
        String startTime = DateUtil.toUtcDateTime(DateUtil.addMinute(date, addMinute));
        String param = ERROR_LOG_PARAM.replaceAll("#startTime#", startTime).replaceAll("#size#", "" + size);

        //发起请求---请求地址格式  http://0.0.0.0:9200/your_indx/_search
        String index = "share_log*";
//        String index = "share_log_"+ DateExtUtil.getDate();
        String url = ES_ROOT_URL + "/" + index + "/_search";
        try {
            log.info("正在请求url={}", url);
            String res = HttpUtil.post(url, param);
            log.info("响应结果={}", res);

            List<JSONObject> hits = (List<JSONObject>) JSONPath.eval(res, "$.hits.hits");
            if (!CollectionUtils.isEmpty(hits)) {
                Map<String, JSONObject> map = new HashMap<>();
                for (JSONObject json : hits) {
                    String applicationName = StrUtil.getValue(json.getString("application_name"), "");
                    String classpath = StrUtil.getValue(json.getString("classpath"), "");
                    String lineNumber = StrUtil.getValue(json.getString("line_number"), "");
                    String key = applicationName + classpath + lineNumber;

                    if (!map.containsKey(key)) {
                        map.put(key, json.getJSONObject("_source"));
                    }
                }

                String jres = JSON.toJSONString(map.values());
                log.info("待发钉钉的消息={}", jres);
                String title = "es异常日志";
                String content = title + " " + DateUtil.getDateTime() + System.lineSeparator() + jres;
                DingDingUtil.sendMdMsg(title, content);
            }
        } catch (Exception e) {
            log.error("请求异常url={}", url, e);
        }

        LocalDateTime end = LocalDateTime.now();
        String msg = "共耗时：{}毫秒";
        long costTime = Duration.between(start, end).toMillis();
        log.info(msg, costTime);
        XxlJobHelper.log(msg, costTime);
    }

    public static void main(String[] args) throws Exception {
        new EsErrorLogJob().sendEsErrorLog();
    }
}
